package com.example.toy.core.conf;

import com.example.toy.core.utils.DurationUtils;
import lombok.Data;

import java.io.IOException;
import java.io.OutputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * SimpleConfig
 *
 * @author shenbing
 * @date 2021/12/21
 */
@Data
public class SimpleConfig {

  private final Properties properties;

  public void setConf(String key, String value) {
    properties.setProperty(key, value);
  }

  public void setIfMissing(String key, String value) {
    if (!properties.containsKey(key)) {
      properties.setProperty(key, value);
    }
  }

  public String getString(String key, String defaultValue) {
    return properties.getProperty(key, defaultValue);
  }

  public Optional<String> getStringOptional(String key) {
    String value = properties.getProperty(key);
    return Optional.ofNullable(value);
  }

  public String getString(String key) {
    return getStringOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public boolean getBool(String key, boolean defaultValue) {
    return getBoolOptional(key).orElse(defaultValue);
  }

  public Optional<Boolean> getBoolOptional(String key) {
    return getStringOptional(key).map(Boolean::parseBoolean);
  }

  public boolean getBool(String key) {
    return getBoolOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public long getLong(String key, long defaultValue) {
    return getLongOptional(key).orElse(defaultValue);
  }

  public Optional<Long> getLongOptional(String key) {
    return getStringOptional(key).map(Long::parseLong);
  }

  public long getLong(String key) {
    return getLongOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public double getDouble(String key, double defaultValue) {
    return getDoubleOptional(key).orElse(defaultValue);
  }

  public Optional<Double> getDoubleOptional(String key) {
    return getStringOptional(key).map(Double::parseDouble);
  }

  public double getDouble(String key) {
    return getDoubleOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public int getInt(String key, int defaultValue) {
    return getIntOptional(key).orElse(defaultValue);
  }

  public Optional<Integer> getIntOptional(String key) {
    return getStringOptional(key).map(Integer::parseInt);
  }

  public int getInt(String key) {
    return getIntOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public float getFloat(String key, float defaultValue) {
    return getFloatOptional(key).orElse(defaultValue);
  }

  public Optional<Float> getFloatOptional(String key) {
    return getStringOptional(key).map(Float::parseFloat);
  }

  public float getFloat(String key) {
    return getFloatOptional(key)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }

  public List<String> getTrimmedList(String key) {
    Optional<String> stringOptional = getStringOptional(key);
    if (stringOptional.isPresent()) {
      String[] split = stringOptional.get().split(",");
      return Arrays.stream(split).map(String::trim).collect(Collectors.toList());
    } else {
      return new ArrayList<>();
    }
  }

  public Optional<Duration> getDurationOptional(String key) {
    return getStringOptional(key).map(DurationUtils::parseDuration);
  }

  public Duration getDuration(String key, String defaultValue) {
    String durationText = getString(key, defaultValue);
    return DurationUtils.parseDuration(durationText);
  }

  public Duration getDuration(String key, Duration defaultValue) {
    return getDurationOptional(key).orElse(defaultValue);
  }

  public Duration getDuration(String key) {
    return getStringOptional(key)
        .map(DurationUtils::parseDuration)
        .orElseThrow(() -> new IllegalArgumentException("Can not find key: " + key));
  }


  public void store(OutputStream configStream) throws IOException {
    this.getProperties().store(configStream, "");
  }
}
